package p.lodz.pl.poid.zad2.segmentation;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import p.lodz.pl.poid.zad2.controller.SegmentationData;

/**
 *
 * @author janiu
 */
public class SegmentationProcessor {
    
    private BufferedImage resultImage; 
    private final SegmentationData data;
    private QuadTree tree;
    private QuadNode selectedNode = null;
    private List<Color> colors;
    private Random rand = new Random();
    private boolean showSelected = false;
    public MaskRegion selectedRegion;
    private static Color transparent = new Color(1f, 1f, 1f, 0.6f);
        
    public SegmentationProcessor(SegmentationData data) {
        this.data = data;     
    }
    
    public void performSegmentation(BufferedImage image) {
        IPixelComparer comparer = chooseComparer();
        this.tree = new QuadTree(image);
        this.tree.setPixelComperer(comparer);
        this.tree.process();
        prepareSelectedNode();
        this.resultImage = paintComponent(image);
    }
    
    private void prepareSelectedNode() {
        Integer regionNumber = data.getRegionNumber();
        if(regionNumber != null) {
            showSelected = true;
            selectedNode = new ArrayList<>(getRegions().values()).get(regionNumber);
        } else {
            showSelected = false;
            selectedNode = null;
        }
    }
    
    private IPixelComparer chooseComparer() {
        if(data.isEuclideanComparison()) {
            return new EuclideanPixelComparer(data.getValue());            
        }
        if(data.isLuminanceComparison()) {
            return new SimplePixelComparer(data.getValue());
        }
        return new SimplePixelComparer(data.getValue());
    }
    
    protected BufferedImage paintComponent(BufferedImage image) {
        ColorModel cm = image.getColorModel();
        Boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
        WritableRaster raster = image.copyData(null);
        BufferedImage resultImage = new BufferedImage(cm, raster, isAlphaPremultiplied, null);
        Graphics g = resultImage.createGraphics();
        paintTree(g);
        return resultImage;
    }
    
    public void paintTree(Graphics g) {
        if (tree != null) {
            if (colors == null) {
                colors = new ArrayList<>();
            }
            int counter = 0;
            if (tree.regions != null) {
                for (MaskRegion region : tree.regions) {
                    if (colors.size() < tree.regions.size()) {
                        colors.add(new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat()));
                    }
                    Color color = getFillColor(region, colors.get(counter));
                    paintTreeRegion(g, region, color, data.isShowGrid(), ((data.getFillOption() == 1 || (selectedRegion != null && (region.equals(selectedRegion) && data.getFillOption() == 2)) || data.getFillOption() > 2) && color != null));
                    counter++;
                }
            }
            if (selectedNode != null && showSelected) {
                g.setColor(Color.GREEN);
                if (data.isShowGrid() && selectedNode.area.width > 1) {
                    g.fillRect(selectedNode.area.x + 1, selectedNode.area.y + 1, selectedNode.area.width - 1, selectedNode.area.height - 1);
                } else {
                    g.fillRect(selectedNode.area.x, selectedNode.area.y, selectedNode.area.width, selectedNode.area.height);
                }
                g.setColor(Color.BLUE);
                if (data.isShowGrid() && selectedNode.area.width > 1) {
                    g.fillRect(selectedNode.area.x + 1, selectedNode.area.y + 1, selectedNode.area.width - 1, selectedNode.area.height - 1);
                } else {
                    g.fillRect(selectedNode.area.x, selectedNode.area.y, selectedNode.area.width, selectedNode.area.height);
                }
            }
        }
    }
    
    public void paintTreeRegion(Graphics g, MaskRegion region, Color color, boolean grid, boolean fill) {
        for (QuadNode node : region.QuadeNodeList.values()) {
            if (grid && node.area.width > 1) {
                g.setColor(Color.black);
                g.drawRect(node.area.x, node.area.y, node.area.width, node.area.height);
            }
            if (fill) {
                g.setColor(color);
                if (grid && node.area.width > 1) {
                    g.fillRect(node.area.x + 1, node.area.y + 1, node.area.width - 1, node.area.height - 1);
                } else {
                    g.fillRect(node.area.x, node.area.y, node.area.width, node.area.height);
                }
            }
        }
    }

    private Color getFillColor(MaskRegion region, Color randomColor) {
        switch (data.getFillOption()) {
            case 0:
                return null;
            case 1:
                return data.isColorArea() ? region.avrageColor : randomColor;
            case 2:
                if (region.equals(selectedRegion)) {
                    return data.isColorArea() ? region.avrageColor : randomColor;
                } else {
                    return null;
                }
            case 3:
                Color one3 = !data.isInverse() ? Color.WHITE : Color.BLACK;
                Color two3 = data.isInverse() ? Color.WHITE : Color.BLACK;
                return region.equals(selectedRegion) ? one3 : two3;

            case 4:
                Color one4 = !data.isInverse() ? null : Color.BLACK;
                Color two4 = data.isInverse() ? null : Color.BLACK;
                return region.equals(selectedRegion) ? one4 : two4;
            default:
                return randomColor;
        }
    }
    
    public HashMap<Integer, QuadNode> getRegions() {
        return tree.QuadeNodeList;
    }

    public BufferedImage getResultImage() {
        return resultImage;
    }

    public void setResultImage(BufferedImage resultImage) {
        this.resultImage = resultImage;
    }

    public QuadTree getTree() {
        return tree;
    }

    public void setTree(QuadTree tree) {
        this.tree = tree;
    }

    public QuadNode getSelectedNode() {
        return selectedNode;
    }

    public void setSelectedNode(QuadNode selectedNode) {
        this.selectedNode = selectedNode;
    }

    public List<Color> getColors() {
        return colors;
    }

    public void setColors(List<Color> colors) {
        this.colors = colors;
    }

    public Random getRand() {
        return rand;
    }

    public void setRand(Random rand) {
        this.rand = rand;
    }

    public boolean isShowSelected() {
        return showSelected;
    }

    public void setShowSelected(boolean showSelected) {
        this.showSelected = showSelected;
    }
    
    public MaskRegion getSelectedRegion() {
        return selectedRegion;
    }

    public void setSelectedRegion(MaskRegion selectedRegion) {
        this.selectedRegion = selectedRegion;
    }

    public static Color getTransparent() {
        return transparent;
    }

    public static void setTransparent(Color transparent) {
        SegmentationProcessor.transparent = transparent;
    }
    
}
